<template>
	<view
		class="lime-signature"
		v-if="show"
		:style="[canvasStyle, styles]"
		ref="limeSignature"
	>
		<!-- #ifndef APP-VUE || APP-NVUE -->
		<!-- {{offscreenId}} -->
		<canvas
			v-if="useCanvas2d"
			class="lime-signature__canvas"
			:id="canvasId"
			type="2d"
			:disableScroll="disableScroll"
			@touchstart="touchStart"
			@touchmove="touchMove"
			@touchend="touchEnd"
		></canvas>
		<canvas
			v-else
			:disableScroll="disableScroll"
			class="lime-signature__canvas"
			:canvas-id="canvasId"
			:id="canvasId"
			:width="canvasWidth"
			:height="canvasHeight"
			@touchstart="touchStart"
			@touchmove="touchMove"
			@touchend="touchEnd"
			@mousedown="touchStart"
			@mousemove="touchMove"
			@mouseup="touchEnd"
		></canvas>
		<canvas
			class="offscreen"
			canvas-id="offscreen"
			id="offscreen"
			:style="
				'width:' +
				offscreenSize[0] +
				'px;height:' +
				offscreenSize[1] +
				'px'
			"
			:width="offscreenSize[0]"
			:height="offscreenSize[1]"
		>
		</canvas>
		<!-- #endif -->
		<!-- #ifdef APP-VUE -->
		<view
			:id="canvasId"
			:disableScroll="disableScroll"
			:rparam="param"
			:change:rparam="sign.update"
			:rclear="rclear"
			:change:rclear="sign.clear"
			:rundo="rundo"
			:change:rundo="sign.undo"
			:rsave="rsave"
			:change:rsave="sign.save"
			:rempty="rempty"
			:change:rempty="sign.isEmpty"
		></view>
		<!-- #endif -->
		<!-- #ifdef APP-NVUE -->
		<web-view
			src="/uni_modules/lime-signature/static/index.html"
			class="lime-signature__canvas"
			ref="webview"
			@pagefinish="onPageFinish"
			@error="onError"
			@onPostMessage="onMessage"
		></web-view>
		<!-- #endif -->
	</view>
</template>
<!-- #ifdef APP-VUE -->
<script module="sign" lang="renderjs">
export {default}  from './render'
</script>
<!-- #endif -->

<script>
// #ifndef APP-NVUE
import {
	canIUseCanvas2d,
	wrapEvent,
	requestAnimationFrame,
	sleep,
} from './utils'
import { Signature } from './signature'
// import {Signature} from '@signature';
import { uniContext, createImage, toDataURL } from './context'
// #endif
import props from './props'
import { base64ToPath, getRect } from './utils'
export default {
	props,
	data() {
		return {
			canvasWidth: null,
			canvasHeight: null,
			useCanvas2d: true,
			show: true,
			offscreenStyles: '',
			// #ifdef APP-PLUS
			rclear: 0,
			rundo: 0,
			rsave: 0,
			rempty: 0,
			risEmpty: true,
			toDataURL: null,
			tempFilePath: [],
			// #endif
		}
	},
	computed: {
		canvasId() {
			return `lime-signature${this._uid || this._.uid}`
		},
		offscreenId() {
			return this.canvasId + 'offscreen'
		},
		offscreenSize() {
			const { canvasWidth, canvasHeight } = this
			return this.landscape
				? [canvasHeight, canvasWidth]
				: [canvasWidth, canvasHeight]
		},
		canvasStyle() {
			const { canvasWidth, canvasHeight, backgroundColor } = this
			return {
				width: canvasWidth && canvasWidth + 'px',
				height: canvasHeight && canvasHeight + 'px',
				background: backgroundColor,
			}
		},
		param() {
			const {
				penColor,
				penSize,
				backgroundColor,
				landscape,
				openSmooth,
				minLineWidth,
				maxLineWidth,
				minSpeed,
				maxWidthDiffRate,
				maxHistoryLength,
				disableScroll,
			} = this
			return JSON.parse(
				JSON.stringify({
					penColor,
					penSize,
					backgroundColor,
					landscape,
					openSmooth,
					minLineWidth,
					maxLineWidth,
					minSpeed,
					maxWidthDiffRate,
					maxHistoryLength,
					disableScroll,
				})
			)
		},
	},
	// #ifdef APP-NVUE
	watch: {
		param(v) {
			this.$refs.webview.evalJS(`update(${JSON.stringify(v)})`)
		},
	},
	// #endif
	// #ifndef APP-PLUS
	created() {
		this.useCanvas2d = this.type == '2d' && canIUseCanvas2d()
	},
	// #endif
	// #ifndef APP-PLUS
	async mounted() {
		if (this.beforeDelay) {
			await sleep(this.beforeDelay)
		}
		const config = await this.getContext()
		this.signature = new Signature(config)
		this.canvasEl = this.signature.canvas.get('el')
		this.canvasWidth = this.signature.canvas.get('width')
		this.canvasHeight = this.signature.canvas.get('height')

		this.stopWatch = this.$watch(
			'param',
			(v) => {
				this.signature.pen.setOption(v)
			},
			{ immediate: true }
		)
	},
	// #endif
	// #ifndef APP-PLUS
	// #ifdef VUE3
	beforeUnmount() {
		this.stopWatch && this.stopWatch()
		this.signature.destroy()
		this.signature = null
		this.show = false
	},
	// #endif
	// #ifdef VUE2
	beforeDestroy() {
		this.stopWatch && this.stopWatch()
		this.signature.destroy()
		this.show = false
		this.signature = null
	},
	// #endif
	// #endif
	methods: {
		// #ifdef MP-QQ
		// toJSON() { return this },
		// #endif
		// #ifdef APP-PLUS
		onPageFinish() {
			this.$refs.webview.evalJS(`update(${JSON.stringify(this.param)})`)
		},
		onMessage(e = {}) {
			const {
				detail: {
					data: [res],
				},
			} = e
			if (res.event?.save) {
				this.toDataURL = res.event.save
			}
			if (res.event?.changeSize) {
				const { width, height } = res.event.changeSize
			}
			if (res.event.hasOwnProperty('isEmpty')) {
				this.risEmpty = res.event.isEmpty
			}
			if (res.event?.file) {
				this.tempFilePath.push(res.event.file)
				if (this.tempFilePath.length > 7) {
					this.tempFilePath.shift()
				}
				return
			}
			if (res.event?.success) {
				if (res.event.success) {
					this.tempFilePath.push(res.event.success)
					if (this.tempFilePath.length > 8) {
						this.tempFilePath.shift()
					}
					this.toDataURL = this.tempFilePath.join('')
					this.tempFilePath = []
				} else {
					this.$emit('fail', 'canvas no data')
				}
				return
			}
		},
		// #endif
		undo() {
			// #ifdef APP-VUE || APP-NVUE
			this.rundo += 1
			// #endif
			// #ifdef APP-NVUE
			this.$refs.webview.evalJS(`undo()`)
			// #endif
			// #ifndef APP-VUE
			if (this.signature) this.signature.undo()
			// #endif
		},
		clear() {
			// #ifdef APP-VUE || APP-NVUE
			this.rclear += 1
			// #endif
			// #ifdef APP-NVUE
			this.$refs.webview.evalJS(`clear()`)
			// #endif
			// #ifndef APP-VUE
			if (this.signature) this.signature.clear()
			// #endif
		},
		isEmpty() {
			// #ifdef APP-NVUE
			this.$refs.webview.evalJS(`isEmpty()`)
			// #endif
			// #ifdef APP-VUE || APP-NVUE
			this.rempty += 1
			// #endif
			// #ifndef APP-VUE || APP-NVUE
			return this.signature.isEmpty()
			// #endif
		},
		canvasToTempFilePath(param) {
			const isEmpty = this.isEmpty()
			// #ifdef APP-NVUE
			this.$refs.webview.evalJS(`save()`)
			// #endif
			// #ifdef APP-VUE || APP-NVUE
			const stopURLWatch = this.$watch('toDataURL', (v, n) => {
				if (v && v !== n) {
					// if(param.pathType == 'url') {
					base64ToPath(v).then((res) => {
						param.success({
							tempFilePath: res,
							isEmpty: this.risEmpty,
						})
					})
					// } else {
					// 	param.success({tempFilePath: v,isEmpty: this.risEmpty })
					// }
					this.toDataURL = ''
				}
				stopURLWatch && stopURLWatch()
			})
			this.rsave += 1
			// #endif
			// #ifndef APP-VUE || APP-NVUE
			const success = (success) => param.success && param.success(success)
			const fail = (fail) => param.fail && param.fail(err)
			const { canvas } = this.signature.canvas.get('el')
			const { backgroundColor, landscape } = this
			const width = this.signature.canvas.get('width')
			const height = this.signature.canvas.get('height')

			const canvasToTempFilePath = (image) => {
				const context = uni.createCanvasContext('offscreen', this)
				context.save()
				context.setTransform(1, 0, 0, 1, 0, 0)
				if (landscape) {
					context.translate(0, width)
					context.rotate(-Math.PI / 2)
				}
				if (backgroundColor) {
					context.fillStyle = backgroundColor
					context.fillRect(0, 0, width, height)
				}
				context.drawImage(image, 0, 0, width, height)

				context.draw(false, () => {
					toDataURL('offscreen', this, param).then((res) => {
						const size = Math.max(width, height)
						context.restore()
						context.clearRect(0, 0, size, size)
						success({ tempFilePath: res, isEmpty })
					})
				})
			}

			if (this.useCanvas2d) {
				try {
					// #ifndef MP-ALIPAY
					base64ToPath(canvas.toDataURL()).then(canvasToTempFilePath)
					// #endif
					// #ifdef MP-ALIPAY
					canvas.toTempFilePath({
						canvasid: this.canvasid,
						success(res) {
							canvasToTempFilePath(res.tempFilePath)
						},
						fail,
					})
					// #endif
				} catch (err) {
					fail(err)
				}
			} else {
				toDataURL(this.canvasId, this)
					.then(canvasToTempFilePath)
					.catch(fail)
			}
			// #endif
		},
		// #ifndef APP-PLUS
		getContext() {
			return getRect(`#${this.canvasId}`, {
				context: this,
				type: this.useCanvas2d ? 'fields' : 'boundingClientRect',
			}).then((res) => {
				if (res) {
					let { width, height, node: canvas, left, top, right } = res
					let { pixelRatio } = uni.getSystemInfoSync()
					let context
					if (canvas) {
						context = canvas.getContext('2d')
						canvas.width = width * pixelRatio
						canvas.height = height * pixelRatio
					} else {
						pixelRatio = 1
						context = uniContext(
							uni.createCanvasContext(this.canvasId, this)
						)
						canvas = {
							createImage,
							toDataURL: () => toDataURL(this.canvasId, this),
							requestAnimationFrame,
						}
					}
					// 支付宝小程序 使用stroke有个默认背景色
					context.clearRect(0, 0, width, height)
					return {
						left,
						top,
						right,
						width,
						height,
						context,
						canvas,
						pixelRatio,
					}
				}
			})
		},
		touchStart(e) {
			if (!this.canvasEl) return
			this.isStart = true
			this.canvasEl.dispatchEvent('touchstart', wrapEvent(e))
		},
		touchMove(e) {
			if (!this.canvasEl || (!this.isStart && this.canvasEl)) return
			this.canvasEl.dispatchEvent('touchmove', wrapEvent(e))
		},
		touchEnd(e) {
			if (!this.canvasEl) return
			this.isStart = false
			this.canvasEl.dispatchEvent('touchend', wrapEvent(e))
		},
		// #endif
	},
}
</script>
<style lang="stylus">
.lime-signature,.lime-signature__canvas
	width: 100%;
	height: 100%
	flex: 1;
.offscreen {
	position: fixed;
	top: 0
	left: 1500rpx;
}
</style>
